{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "e82e44e1",
   "metadata": {},
   "source": [
    "## Load Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "d67b3443",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['vision_language_2d_demo.ipynb', 'categorical_2d_demo.ipynb', '.ipynb_checkpoints']\n"
     ]
    }
   ],
   "source": [
    "import glob\n",
    "import torch\n",
    "import numpy as np\n",
    "import warnings\n",
    "warnings.simplefilter(\"ignore\")\n",
    "import os"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "b64635de",
   "metadata": {},
   "outputs": [
    {
     "ename": "RuntimeError",
     "evalue": "stack expects a non-empty TensorList",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mRuntimeError\u001b[0m                              Traceback (most recent call last)",
      "Cell \u001b[0;32mIn [2], line 5\u001b[0m\n\u001b[1;32m      2\u001b[0m pose_delta_paths \u001b[38;5;241m=\u001b[39m glob\u001b[38;5;241m.\u001b[39mglob(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdemo_data/pose_delta_*.npy\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m      3\u001b[0m device \u001b[38;5;241m=\u001b[39m torch\u001b[38;5;241m.\u001b[39mdevice(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcuda:0\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m----> 5\u001b[0m obs \u001b[38;5;241m=\u001b[39m \u001b[43mtorch\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mstack\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\n\u001b[1;32m      6\u001b[0m \u001b[43m    \u001b[49m\u001b[43mtorch\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfrom_numpy\u001b[49m\u001b[43m(\u001b[49m\u001b[43mnp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mload\u001b[49m\u001b[43m(\u001b[49m\u001b[43mobs_path\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\u001b[43m \u001b[49m\n\u001b[1;32m      7\u001b[0m \u001b[43m    \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mobs_path\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mobs_paths\u001b[49m\n\u001b[1;32m      8\u001b[0m \u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241m.\u001b[39munsqueeze(\u001b[38;5;241m0\u001b[39m)\u001b[38;5;241m.\u001b[39mto(device)\n\u001b[1;32m     10\u001b[0m pose_delta \u001b[38;5;241m=\u001b[39m torch\u001b[38;5;241m.\u001b[39mstack([\n\u001b[1;32m     11\u001b[0m     torch\u001b[38;5;241m.\u001b[39mfrom_numpy(np\u001b[38;5;241m.\u001b[39mload(pose_delta_path)) \n\u001b[1;32m     12\u001b[0m     \u001b[38;5;28;01mfor\u001b[39;00m pose_delta_path \u001b[38;5;129;01min\u001b[39;00m pose_delta_paths\n\u001b[1;32m     13\u001b[0m ])\u001b[38;5;241m.\u001b[39munsqueeze(\u001b[38;5;241m0\u001b[39m)\u001b[38;5;241m.\u001b[39mto(device)\n",
      "\u001b[0;31mRuntimeError\u001b[0m: stack expects a non-empty TensorList"
     ]
    }
   ],
   "source": [
    "obs_paths = glob.glob(\"demo_data/obs_*.npy\")\n",
    "pose_delta_paths = glob.glob(\"demo_data/pose_delta_*.npy\")\n",
    "device = torch.device(\"cuda:0\")\n",
    "\n",
    "obs = torch.stack([\n",
    "    torch.from_numpy(np.load(obs_path)) \n",
    "    for obs_path in obs_paths\n",
    "]).unsqueeze(0).to(device)\n",
    "\n",
    "pose_delta = torch.stack([\n",
    "    torch.from_numpy(np.load(pose_delta_path)) \n",
    "    for pose_delta_path in pose_delta_paths\n",
    "]).unsqueeze(0).to(device)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "007ddec2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([1, 70, 20, 480, 640])"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# frame containing (RGB, depth, segmentation) of shape \n",
    "# (batch_size, sequence_length, 3 + 1 + num_sem_categories, frame_height, frame_width)\n",
    "obs.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "fb32c249",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([1, 70, 3])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# sensor pose delta (dy, dx, dtheta) since last frame of shape \n",
    "# (batch_size, sequence_length, 3)\n",
    "pose_delta.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f4578e76",
   "metadata": {},
   "source": [
    "## Map Initialization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "487b019c",
   "metadata": {},
   "outputs": [],
   "source": [
    "from home_robot.agent.mapping.dense.semantic.categorical_2d_semantic_map_state import Categorical2DSemanticMapState\n",
    "from home_robot.agent.mapping.dense.semantic.categorical_2d_semantic_map_module import Categorical2DSemanticMapModule\n",
    "\n",
    "# State holds global and local map and sensor pose\n",
    "# See class definition for argument info\n",
    "semantic_map = Categorical2DSemanticMapState(\n",
    "    device=device,\n",
    "    num_environments=1,\n",
    "    num_sem_categories=16,\n",
    "    map_resolution=5,\n",
    "    map_size_cm=4800,\n",
    "    global_downscaling=2,\n",
    ")\n",
    "semantic_map.init_map_and_pose()\n",
    "\n",
    "# Module is responsible for updating the local and global maps and poses\n",
    "# See class definition for argument info\n",
    "semantic_map_module = Categorical2DSemanticMapModule(\n",
    "    frame_height=480,\n",
    "    frame_width=640,\n",
    "    camera_height=0.88,\n",
    "    hfov=79.0,\n",
    "    num_sem_categories=16,\n",
    "    map_size_cm=4800,\n",
    "    map_resolution=5,\n",
    "    vision_range=100,\n",
    "    global_downscaling=2,\n",
    "    du_scale=4,\n",
    "    cat_pred_threshold=5.0,\n",
    "    exp_pred_threshold=1.0,\n",
    "    map_pred_threshold=1.0,\n",
    ").to(device)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "14f7b71e",
   "metadata": {},
   "source": [
    "## Map Update"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "93d51bfd",
   "metadata": {},
   "outputs": [],
   "source": [
    "sequence_length = obs.shape[1]\n",
    "num_sem_categories = obs.shape[2] - 4\n",
    "dones = torch.tensor([False] * sequence_length).unsqueeze(0).to(device)\n",
    "update_global = torch.tensor([True] * sequence_length).unsqueeze(0).to(device)\n",
    "\n",
    "(\n",
    "    seq_map_features,\n",
    "    semantic_map.local_map,\n",
    "    semantic_map.global_map,\n",
    "    seq_local_pose,\n",
    "    seq_global_pose,\n",
    "    seq_lmb,\n",
    "    seq_origins,\n",
    ") = semantic_map_module(\n",
    "    obs,\n",
    "    pose_delta,\n",
    "    dones,\n",
    "    update_global,\n",
    "    semantic_map.local_map,\n",
    "    semantic_map.global_map,\n",
    "    semantic_map.local_pose,\n",
    "    semantic_map.global_pose,\n",
    "    semantic_map.lmb,\n",
    "    semantic_map.origins,\n",
    ")\n",
    "    \n",
    "semantic_map.local_pose = seq_local_pose[:, -1]\n",
    "semantic_map.global_pose = seq_global_pose[:, -1]\n",
    "semantic_map.lmb = seq_lmb[:, -1]\n",
    "semantic_map.origins = seq_origins[:, -1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "16e7df32",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([1, 20, 960, 960])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Global semantic map of shape \n",
    "# (batch_size, num_channels, M, M)\n",
    "#\n",
    "# where num_channels = 4 + num_sem_categories\n",
    "# 0: obstacle map\n",
    "# 1: explored area\n",
    "# 2: current agent location\n",
    "# 3: past agent locations\n",
    "# 4, 5, 6, .., num_sem_categories + 3: semantic categories\n",
    "semantic_map.global_map.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "ee53d178",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x7f1499e61350>"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAakAAAGiCAYAAABd6zmYAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAABfX0lEQVR4nO3deXBV150v+u8ezqx5QEIDiEGAQWBmjBjN5Dh2nKE7TiepXHd1XlXSiV2h7Lx0nNSrTm7dMu7c1053KrfTle5+cd/u5HFfd2wnt9txwMGIGYQGRptRIAQSEiA0nXnv9f44XotzNICEjtAWfD9Vp0D77HPOPluwf3ut9Vu/pQkhBIiIiBxIH+8DICIiGgqDFBERORaDFBERORaDFBERORaDFBERORaDFBERORaDFBERORaDFBERORaDFBERORaDFBEROda4Bqm/+7u/w7Rp0+D1erFkyRLs3bt3PA+HiIgcZtyC1P/6X/8LW7duxfe//300NDRgzZo1ePrpp9Hc3Dxeh0RERA6jjVeB2RUrVmDx4sX42c9+prY99thj+MxnPoNt27aNxyEREZHDmOPxodFoFHV1dfjud7+bsn3Lli04cODAgP0jkQgikYj62bZt3Lp1C/n5+dA0bcyPl4iI0ksIgZ6eHpSUlEDXh+7UG5cgdePGDViWhaKiopTtRUVFaGtrG7D/tm3b8MMf/vBBHR4RET0gV65cQVlZ2ZDPj0uQkvq3goQQg7aMXn31Vbz88svq566uLkyZMgVXrlxBVlbWmB8nERGlV3d3N8rLy5GZmXnX/cYlSBUUFMAwjAGtpvb29gGtKwDweDzweDwDtmdlZTFIERFNYPcashmX7D63240lS5Zg586dKdt37tyJ6urq8TgkIiJyoHHr7nv55Zfxla98BUuXLsXKlSvx85//HM3Nzfj6178+XodEREQOM25B6gtf+AJu3ryJ//pf/ytaW1tRVVWFd999F1OnTh2vQyIiIocZt3lSo9Hd3Y3s7Gx0dXVxTIqIaAIa7nWctfuIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixGKSIiMixRhyk9uzZg0996lMoKSmBpml45513Up4XQuAHP/gBSkpK4PP5sH79epw6dSpln0gkgpdeegkFBQUIBAJ47rnn0NLSMqovQkRED58RB6m+vj48/vjj+OlPfzro8z/60Y/wxhtv4Kc//Slqa2tRXFyMzZs3o6enR+2zdetWvP3229i+fTv27duH3t5ePPvss7As6/6/CRERPXzEKAAQb7/9tvrZtm1RXFwsXn/9dbUtHA6L7Oxs8fd///dCCCFu374tXC6X2L59u9rn6tWrQtd18d577w3rc7u6ugQA0dXVNZrDJyKicTLc63hax6SamprQ1taGLVu2qG0ejwfr1q3DgQMHAAB1dXWIxWIp+5SUlKCqqkrt018kEkF3d3fKg4iIHn5pDVJtbW0AgKKiopTtRUVF6rm2tja43W7k5uYOuU9/27ZtQ3Z2tnqUl5en87CJiMihxiS7T9O0lJ+FEAO29Xe3fV599VV0dXWpx5UrV9J2rERE5FxpDVLFxcUAMKBF1N7erlpXxcXFiEaj6OzsHHKf/jweD7KyslIeRET08EtrkJo2bRqKi4uxc+dOtS0ajaKmpgbV1dUAgCVLlsDlcqXs09raipMnT6p9iIiIAMAc6Qt6e3tx/vx59XNTUxMaGxuRl5eHKVOmYOvWrXjttddQWVmJyspKvPbaa/D7/fjSl74EAMjOzsZXv/pVvPLKK8jPz0deXh6+/e1vY/78+di0aVP6vhkREU14Iw5SR48exZNPPql+fvnllwEAL7zwAt5880185zvfQSgUwje+8Q10dnZixYoV2LFjBzIzM9VrfvzjH8M0TTz//PMIhULYuHEj3nzzTRiG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BXbs2IHMzEy1z49//GOYponnn38eoVAIGzduxJtvvgnDMNJ9OERENIFpQggx3gcxUt3d3cjOzkZXVxfHp4iIJqDhXsdZu4+IiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiBzLHO8DuB9CCABAd3f3OB8JERHdD3n9ltfzoUzIINXT0wMAKC8vH+cjISKi0ejp6UF2dvaQz2viXmHMgWzbxpkzZzB37lxcuXIFWVlZ431IE0J3dzfKy8t5zkaA52zkeM5G7lE8Z0II9PT0oKSkBLo+9MjThGxJ6bqO0tJSAEBWVtYj80tNF56zkeM5Gzmes5F71M7Z3VpQEhMniIjIsRikiIjIsSZskPJ4PPjLv/xLeDye8T6UCYPnbOR4zkaO52zkeM6GNiETJ4iI6NEwYVtSRET08GOQIiIix2KQIiIix2KQIiIix5qQQerv/u7vMG3aNHi9XixZsgR79+4d70MaN3v27MGnPvUplJSUQNM0vPPOOynPCyHwgx/8ACUlJfD5fFi/fj1OnTqVsk8kEsFLL72EgoICBAIBPPfcc2hpaXmA3+LB2bZtG5YtW4bMzExMmjQJn/nMZ3DmzJmUfXjOUv3sZz/DggUL1ETTlStX4ne/+516nufr3rZt2wZN07B161a1jedtmMQEs337duFyucQ//MM/iNOnT4tvfetbIhAIiMuXL4/3oY2Ld999V3z/+98Xv/71rwUA8fbbb6c8//rrr4vMzEzx61//Wpw4cUJ84QtfEJMnTxbd3d1qn69//euitLRU7Ny5U9TX14snn3xSPP744yIejz/gbzP2nnrqKfGLX/xCnDx5UjQ2NopnnnlGTJkyRfT29qp9eM5S/fa3vxX/+Z//Kc6cOSPOnDkjvve97wmXyyVOnjwphOD5upcjR46IiooKsWDBAvGtb31Lbed5G54JF6SWL18uvv71r6dsmzNnjvjud787TkfkHP2DlG3bori4WLz++utqWzgcFtnZ2eLv//7vhRBC3L59W7hcLrF9+3a1z9WrV4Wu6+K99957YMc+Xtrb2wUAUVNTI4TgORuu3Nxc8Y//+I88X/fQ09MjKisrxc6dO8W6detUkOJ5G74J1d0XjUZRV1eHLVu2pGzfsmULDhw4ME5H5VxNTU1oa2tLOV8ejwfr1q1T56uurg6xWCxln5KSElRVVT0S57SrqwsAkJeXB4Dn7F4sy8L27dvR19eHlStX8nzdwze/+U0888wz2LRpU8p2nrfhm1AFZm/cuAHLslBUVJSyvaioCG1tbeN0VM4lz8lg5+vy5ctqH7fbjdzc3AH7POznVAiBl19+GatXr0ZVVRUAnrOhnDhxAitXrkQ4HEZGRgbefvttzJ07V10seb4G2r59O+rr61FbWzvgOf47G74JFaQkTdNSfhZCDNhGd9zP+XoUzumLL76I48ePY9++fQOe4zlLNXv2bDQ2NuL27dv49a9/jRdeeAE1NTXqeZ6vVFeuXMG3vvUt7NixA16vd8j9eN7ubUJ19xUUFMAwjAF3Ee3t7QPuSAgoLi4GgLuer+LiYkSjUXR2dg65z8PopZdewm9/+1t88MEHKCsrU9t5zgbndrsxc+ZMLF26FNu2bcPjjz+Ov/3bv+X5GkJdXR3a29uxZMkSmKYJ0zRRU1ODn/zkJzBNU31vnrd7m1BByu12Y8mSJdi5c2fK9p07d6K6unqcjsq5pk2bhuLi4pTzFY1GUVNTo87XkiVL4HK5UvZpbW3FyZMnH8pzKoTAiy++iLfeegu7du3CtGnTUp7nORseIQQikQjP1xA2btyIEydOoLGxUT2WLl2KL3/5y2hsbMT06dN53oZrfPI17p9MQf+nf/oncfr0abF161YRCATEpUuXxvvQxkVPT49oaGgQDQ0NAoB44403RENDg0rJf/3110V2drZ46623xIkTJ8QXv/jFQdNcy8rKxPvvvy/q6+vFhg0bHto01z//8z8X2dnZYvfu3aK1tVU9gsGg2ofnLNWrr74q9uzZI5qamsTx48fF9773PaHrutixY4cQgudruJKz+4TgeRuuCRekhBDif/yP/yGmTp0q3G63WLx4sUoffhR98MEHAsCAxwsvvCCESKS6/uVf/qUoLi4WHo9HrF27Vpw4cSLlPUKhkHjxxRdFXl6e8Pl84tlnnxXNzc3j8G3G3mDnCoD4xS9+ofbhOUv1Z3/2Z+r/W2Fhodi4caMKUELwfA1X/yDF8zY8XKqDiIgca0KNSRER0aOFQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiByLQYqIiBzr/wdwEv7oCD+0xgAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Local semantic map visualization\n",
    "\n",
    "import cv2\n",
    "from PIL import Image\n",
    "import matplotlib.pyplot as plt\n",
    "from home_robot.agent.perception.detection.coco_maskrcnn.coco_categories import (\n",
    "    coco_categories_color_palette,\n",
    ")\n",
    "\n",
    "map_color_palette = [\n",
    "    1.0,\n",
    "    1.0,\n",
    "    1.0,  # empty space\n",
    "    0.6,\n",
    "    0.6,\n",
    "    0.6,  # obstacles\n",
    "    0.95,\n",
    "    0.95,\n",
    "    0.95,  # explored area\n",
    "    0.96,\n",
    "    0.36,\n",
    "    0.26,  # visited area\n",
    "    *coco_categories_color_palette,\n",
    "]\n",
    "map_color_palette = [int(x * 255.0) for x in map_color_palette]\n",
    "\n",
    "semantic_categories_map = semantic_map.get_semantic_map(0)\n",
    "obstacle_map = semantic_map.get_obstacle_map(0)\n",
    "explored_map = semantic_map.get_explored_map(0)\n",
    "visited_map = semantic_map.get_visited_map(0)\n",
    "\n",
    "semantic_categories_map += 4\n",
    "no_category_mask = semantic_categories_map == 4 + num_sem_categories - 1\n",
    "obstacle_mask = np.rint(obstacle_map) == 1\n",
    "explored_mask = np.rint(explored_map) == 1\n",
    "visited_mask = visited_map == 1\n",
    "semantic_categories_map[no_category_mask] = 0\n",
    "semantic_categories_map[np.logical_and(no_category_mask, explored_mask)] = 2\n",
    "semantic_categories_map[np.logical_and(no_category_mask, obstacle_mask)] = 1\n",
    "semantic_categories_map[visited_mask] = 3\n",
    "\n",
    "semantic_map_vis = Image.new(\"P\", semantic_categories_map.shape)\n",
    "semantic_map_vis.putpalette(map_color_palette)\n",
    "semantic_map_vis.putdata(semantic_categories_map.flatten().astype(np.uint8))\n",
    "semantic_map_vis = semantic_map_vis.convert(\"RGB\")\n",
    "semantic_map_vis = np.flipud(semantic_map_vis)\n",
    "plt.imshow(semantic_map_vis)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:home_robot]",
   "language": "python",
   "name": "conda-env-home_robot-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
